#include <iostream>
#include <fstream>
#include <stack>

#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

#include "huffman.h"


#include "../../include/hzstream.h"

using namespace std;
using namespace hfm;

const static int alphabet_size = 256;


void printUsage(const char * exe) {
	printf( "USAGE:\n"
			"\t%s [options] <input_filename>\n",
			exe);
}

void printHelp(void) {
	cout << "Possible options: " << endl;
	cout << "d -- decoding data" << endl;
	cout << "e -- encoding data" << endl;
	cout << "h -- print this help" << endl;
	cout << "i <filename> -- input file" << endl;
	cout << "o <filename> -- output file" << endl;
	cout << "v -- verbose mode" << endl;
}

/*
 * Entry point for the project
 */
int main(int argc, char** argv) {

	char* in_filename = NULL;
	char* out_filename = NULL;
	fstream input;
	fstream output;
	bool verbose = false;
	bool decoding = false, encoding = false;
	int32_t data_size = 0;
	uint8_t *buf_1;



	HFM* hfm = new HFM();

	hzstream hz;

	if (argc < 2) {
		printUsage(argv[0]);
		return EXIT_SUCCESS;
	}

	// Parsing console parameters
	int c;
	while ( (c = getopt(argc, argv, "dehi:o:s:v")) != -1) {
		switch (c) {
		case 'd':
			decoding = true;
			break;
		case 'e':
			encoding = true;
			break;
		case 'i':
			in_filename = optarg;
			break;
		case 'o':
			out_filename = optarg;
			break;
		case 'v':
			verbose = true;
			break;
		case '?':
		case 'h':
			printHelp();
			return EXIT_SUCCESS;
		default:
			printf("Unknown argument: %c!\n", c);
			return EXIT_FAILURE;
			break;
		}
	}
	if (optind < argc) {
		printf("Too many input files specified!\n");
		return EXIT_FAILURE;
	}

	//Checking if all required parameters are set up

	input.open(in_filename, fstream::in|fstream::binary);
	if(input.fail()){
		cout << "Couldn't open input file: " << in_filename << endl;
		return EXIT_FAILURE;
	} else{
		input.seekg(0, fstream::end);
		data_size = input.tellg();
		if(data_size == -1){
			cout << "Couldn't get input file size: " << in_filename << endl;
			return EXIT_FAILURE;
		}
		input.seekg(0, fstream::beg);
	}

	output.open(out_filename, fstream::out|fstream::trunc|fstream::binary);
	if(output.fail()){
		cout << "Couldn't open output file: " << out_filename << endl;
		return EXIT_FAILURE;
	}


	if((!encoding && !decoding) || (decoding && encoding)){
		cout <<"You must choose one working mode" << endl;
		printHelp();
		return EXIT_FAILURE;
	}


	if(verbose){
		cout << "Program call summary: " << endl;
		cout << "Input filename = " << in_filename << endl;
		cout << "Input data size = " << data_size << endl;
		cout << "Output filename = " << out_filename << endl;
		cout << "Algorithm type: ";
		cout << "Huffman" << endl;
	}

	//Executing encoding/decoding



	if(encoding){

		buf_1 = new uint8_t[data_size];

		input.read(reinterpret_cast<char *>(buf_1), data_size);


		hz.in_buf = buf_1;
		hz.in_size = data_size;

		hfm->encode(&hz);



		output.write((char*)hz.out_buf, hz.out_size);

		hz.in_buf = NULL;
		hz.out_buf = NULL;
		delete[] buf_1;
	}

	if(decoding){

		buf_1 = new uint8_t[data_size];

		input.read(reinterpret_cast<char *>(buf_1), data_size);


		hz.in_buf = buf_1;
		hz.in_size = data_size;

		hfm->decode(&hz);

		hz.in_buf = hz.out_buf;
		hz.in_size = hz.out_size;
		
		output.write((char*)hz.out_buf, hz.out_size);

}
	
	input.close();
	output.close();

	return EXIT_SUCCESS;
}

